package com.tjetc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.tjetc.constant.CommonConstant;
import com.tjetc.context.BaseContext;
import com.tjetc.dao.*;
import com.tjetc.dao.impl.*;
import com.tjetc.exception.MessageException;
import com.tjetc.pojo.dto.CheckInDTO;
import com.tjetc.pojo.dto.HotelDTO;
import com.tjetc.pojo.dto.ReviewDTO;
import com.tjetc.pojo.entity.*;
import com.tjetc.pojo.vo.AmenitiesNameVO;
import com.tjetc.pojo.vo.GuestIdVO;
import com.tjetc.pojo.vo.IncomeVO;
import com.tjetc.service.HotelService;
import com.tjetc.utils.DruidUtils;
import com.tjetc.utils.TimerTaskUtil;
import com.tjetc.view.CommentPage;
import com.tjetc.view.impl.CommentPageImpl;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;

/**
 * @Author: itda
 * @Date: 2024/5/10 16:05
 * @Description: 酒店的业务逻辑
 */
public class HotelServiceImpl implements HotelService {

    private HotelDao hotelDao = new HotelDaoImpl();

    private RoomDao roomDao = new RoomDaoImpl();

    private AmenitiesDao amenitiesDao = new AmenitiesDaoImpl();

    private CommentDao commentDao = new CommentDaoImpl();

    private BookingDao bookingDao = new BookingDaoImpl();

    private OrderDao orderDao = new OrderDaoImpl();

    private CommentPage commentPage = new CommentPageImpl();

    private GuestDao guestDao = new GuestDaoImpl();

    private IncomeDao incomeDao = new IncomeDaoImpl();

    @Override
    public void save(HotelDTO hotelDTO) {
        try {
            if (hotelDao.getById(hotelDTO.getId()) != null) {
                throw new MessageException(CommonConstant.HOTEL_EXIST);
            }
            Hotel hotel = new Hotel();
            BeanUtil.copyProperties(hotelDTO, hotel);
            DruidUtils.start();
            hotelDao.save(hotel);
            DruidUtils.commit();
            System.out.println(CommonConstant.ADD_SUCCESS);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            DruidUtils.rollback();
        }
    }

    @Override
    public void delete(Long hotelId) {
        try {
            DruidUtils.start();
            //删除酒店
            hotelDao.deleteById(hotelId);
            //删除酒店下的所有房间
            roomDao.deleteByHotelId(hotelId);
            //删除酒店下所有的设施
            amenitiesDao.deleteByHotelId(hotelId);
            DruidUtils.commit();
            System.out.println(CommonConstant.DELETE_SUCCESS);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            DruidUtils.rollback();
        }
    }

    @Override
    public void update(HotelDTO hotelDTO) {
        try {
            if (hotelDao.getById(hotelDTO.getId()) == null) {
                throw new MessageException(CommonConstant.NO_FIND_HOTEL);
            }
            DruidUtils.start();
            Hotel hotel = new Hotel();
            BeanUtil.copyProperties(hotelDTO, hotel);
            hotelDao.update(hotel);
            System.out.println(CommonConstant.UPDATE_SUCCESS);
            DruidUtils.commit();
        } catch (Exception e) {
            System.out.println(e.getMessage());
            DruidUtils.rollback();
        }
    }

    @Override
    public void list() throws Exception {
        List<Hotel> list = hotelDao.list();
        if (list == null || list.size() == 0) {
            throw new Exception(CommonConstant.NO_FIND_DATA);
        }
        for (Hotel hotel : list) {
            List<AmenitiesNameVO> amenities= amenitiesDao.getByHotelId(hotel.getId());
            List<String> list1=new ArrayList<>();
            for (int i = 0; i < amenities.size(); i++) {
                list1.add(amenities.get(i).getName());
            }
            hotel.setAmenities(list1);
            System.out.println(hotel);
        }
    }

    @Override
    public void showBasicInfo(Long hotelId) {
        try {
            Hotel hotel = hotelDao.getById(hotelId);
            if (hotel == null) {
                throw new MessageException(CommonConstant.NO_FIND_HOTEL);
            }
            System.out.println("酒店名称:" + hotel.getName());
            System.out.println("酒店地址:" + hotel.getAddress());
            System.out.println("酒店所在城市:" + hotel.getCity());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    @Override
    public void showBasicAmenities(Long hotelId) {
        try {
            Hotel hotel = hotelDao.getById(hotelId);
            if (hotel == null) {
                throw new MessageException(CommonConstant.NO_FIND_HOTEL);
            }
            List<AmenitiesNameVO> list = amenitiesDao.getByHotelId(hotelId);
            if (list == null || list.size() == 0) {
                throw new MessageException(CommonConstant.HOTEL_NO_AMENITIES);
            }
            System.out.println("酒店包括以下基础设施:");
            list.forEach(System.out::println);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }

    @Override
    public void showComment(Long hotelId) {
        try {
            Hotel hotel = hotelDao.getById(hotelId);
            if (hotel == null) {
                throw new MessageException(CommonConstant.NO_FIND_HOTEL);
            }
            List<Review> list = commentDao.getByHotelId(hotelId);
            if (list == null || list.size() == 0) {
                throw new MessageException(CommonConstant.HOTEL_NO_COMMENT);
            }
            System.out.println("酒店包括以下评论信息:");
            list.forEach(System.out::println);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    @Override
    public void showDescription(Long hotelId) {
        try {
            Hotel hotel = hotelDao.getById(hotelId);
            if (hotel == null) {
                throw new MessageException(CommonConstant.NO_FIND_HOTEL);
            }
            System.out.println("酒店的描述如下:");
            System.out.println(hotel.getDescription());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    @Override
    public void checkIn(CheckInDTO checkInDTO) {
        try {
            Booking booking = bookingDao.getByRGId(checkInDTO.getRoomId(), checkInDTO.getGuestId());
            if (booking == null) {
                throw new MessageException(CommonConstant.NO_BOOKINGINFO);
            }
            DruidUtils.start();
            LocalDateTime now = LocalDateTime.now();
            Order order = new Order(null, booking.getRoomId(), booking.getGuestId(), now, booking.getCheckOutDate(), booking.getTotalPrice(), null);
            if (booking.getCheckInDate().isBefore(now)) {
                long hours = Duration.between(booking.getCheckInDate(),now).toHours();
                if (hours < 3) {
                    System.out.println(CommonConstant.EXCEEDING_BOOKING_TIME);
                    //扣除十分之一押金
                    bookingDao.setTotalMoney(booking.getId());
                    order.setTotalPrice(booking.getTotalPrice() * 0.9);
                    order.setStatus(CommonConstant.EXCEEDING_BOOKING_TIME);
                    orderDao.insert(order);
                    roomDao.checkIn(checkInDTO);
                    DruidUtils.commit();
                    return;
                }
                //超过预约时间三个小时自动取消预约
                System.out.println(CommonConstant.EXCEEDING_BOOKING_TIME_TO_MORE);
                bookingDao.setTotalMoney(booking.getId());
                order.setTotalPrice(booking.getTotalPrice() * 0.8);
                order.setCheckInDate(null);
                order.setCheckOutDate(null);
                order.setStatus(CommonConstant.EXCEEDING_BOOKING_TIME_TO_MORE);
                bookingDao.delete(booking.getId());
                System.out.println(CommonConstant.EXCEEDING_BOOKING_TIME_TO_MORE);
                orderDao.insert(order);
                roomDao.updateStatusById(booking.getRoomId(),(short)4);
                DruidUtils.commit();
                return;
            }
            //入住 状态
            roomDao.checkIn(checkInDTO);
            order.setStatus(CommonConstant.CHECK_IN_SUCCESS);
            order.setTotalPrice(booking.getTotalPrice() * Duration.between(booking.getCheckInDate(), booking.getCheckOutDate()).toHours());
            orderDao.insert(order);
            DruidUtils.commit();
            System.out.println(CommonConstant.CHECK_IN_SUCCESS);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            DruidUtils.rollback();
        }
    }

    @Override
    public void checkOut(CheckInDTO checkOut) {
        try {
            Booking booking = bookingDao.getByRGId(checkOut.getRoomId(), checkOut.getGuestId());
            if (booking == null) {
                throw new MessageException(CommonConstant.NO_BOOKINGINFO);
            }
            Room room = roomDao.getById(booking.getRoomId());
            if (room.getAvailability() != 3) {
                throw new MessageException(CommonConstant.ROOM_STATUS_ERROR);
            }
            DruidUtils.start();
            roomDao.updateStatusById(room.getId(), (short) 3);
            LocalDateTime checkOutDate = booking.getCheckOutDate();
            LocalDateTime now = LocalDateTime.now();
            Double price = roomDao.getById(booking.getRoomId()).getPrice();
            double extraCost = 0;
            if (now.isAfter(checkOutDate)){
                System.out.println(CommonConstant.CHECK_OUT_TIME_NO_IN_BOOKING);
                long hours = Duration.between(checkOutDate, now).toHours();
                extraCost = hours * (price+10);
                checkOutDate = now;
            }
            long hours = Duration.between(booking.getCheckInDate(), booking.getCheckOutDate()).toHours();
            Order order = new Order(null, booking.getRoomId(), booking.getGuestId(), booking.getCheckInDate(), checkOutDate, price * hours + extraCost, CommonConstant.CHECK_OUT_SUCCESS);
            IncomeVO incomeVO = IncomeVO.builder().roomId(order.getRoomId()).cost(order.getTotalPrice()).createTime(now).build();
            incomeDao.insert(incomeVO);
            orderDao.insert(order);
            //十五秒后该房间状态自动改为空闲状态
            Timer timer = new Timer();
            timer.schedule(new TimerTaskUtil(room.getId(), (short) 4), 15000);
            bookingDao.delete(booking.getId());
            DruidUtils.commit();
            System.out.println(CommonConstant.CHECK_OUT_SUCCESS);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            DruidUtils.rollback();
        }
    }

    @Override
    public void comment(Long hotelId) {
        try {
            Hotel hotel = hotelDao.getById(hotelId);
            if (hotel==null){
                throw new MessageException(CommonConstant.NO_FIND_HOTEL);
            }
            List<Order> list = orderDao.getByUHId(BaseContext.getCurrentId(),hotelId);
            if (list==null||list.size()==0){
                throw new MessageException(CommonConstant.NO_CONSUMPTION);
            }
            Review review = commentDao.getByUHId(BaseContext.getCurrentId(), hotelId);
            //List<Order> orders = orderDao.getByUHId(BaseContext.getCurrentId(), hotelId);
            if (review!=null){
                throw new MessageException(CommonConstant.ONLY_COMMENT_ONE);
            }
            review = new Review();
            ReviewDTO reviewDTO = commentPage.comment(hotelId);
            BeanUtil.copyProperties(reviewDTO,review);
            GuestIdVO guestIdVO = guestDao.getByUserId(BaseContext.getCurrentId());
            review.setGuestId(guestIdVO.getGuestId());
            double total = reviewDTO.getRating();
            double num = 1;
            List<Review> reviews = commentDao.getByHotelId(hotelId);
            for (Review r : reviews) {
                if (r.getRating()!=0){
                    total+= r.getRating();
                    num++;
                }
            }
            if (num==0){
                throw new MessageException(CommonConstant.HOTEL_NO_RATING);
            }
            DruidUtils.start();
            hotelDao.updateRating(hotelId,total/num);
            commentDao.insert(review);
            DruidUtils.commit();
            System.out.println(CommonConstant.ADD_SUCCESS);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            DruidUtils.rollback();
        }
    }
}
